//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//

#include <windows.h>
#include "CVideoCaptureGraph.h"
#include "motionfilter.h"

#define MotionTimeout 3000

#define MAX_DWORD               0xFFFFFFFF

CVideoCaptureGraph g_VideoCaptureGraph;
DWORD dwMotionDetectedTimeStart = 0;
BOOL bMotionDetected = FALSE;

COLORREF crWhite = RGB(255, 255, 255);

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    long lEventCode, lParam1, lParam2;
    HBRUSH hbrush = NULL;
    DWORD dwCurrentTime = 0;
    DWORD dwTimeElapsed = 0;

    switch (message) 
    {
        case WM_DSHOWEVENT:
            // get the event and process it.
            if(FAILED(g_VideoCaptureGraph.GetEvent(&lEventCode, &lParam1, &lParam2, 0)))
                OutputDebugString(TEXT("Failed to Retrieve the event"));
            else
            {
                if(EC_MOTIONDETECTED == lEventCode)
                {
                    OutputDebugString(TEXT("Motion detected"));
                    dwMotionDetectedTimeStart = GetTickCount();
                    if(!bMotionDetected)
                    {
                        SetTimer(hWnd, 1, 750, NULL);
                        bMotionDetected = TRUE;
                        OutputDebugString(TEXT("Starting a new capture"));
                        g_VideoCaptureGraph.StartCapture();
                    }
                }
                else if(EC_STREAM_CONTROL_STARTED == lEventCode)
                {
                    OutputDebugString(TEXT("Received the stream control started event"));
                }
                else if(EC_STREAM_CONTROL_STOPPED == lEventCode)
                {
                    OutputDebugString(TEXT("Received the stream control stopped event"));
                }

                g_VideoCaptureGraph.FreeEvent(lEventCode, lParam1, lParam2);
            }
            break;
        case WM_CREATE:
            if(FAILED(g_VideoCaptureGraph.BuildGraph(hWnd, NULL)))
            {
                // notify the user and exit the app
                MessageBox(NULL, TEXT("Failed to build the capture graph, exiting"), TEXT("Error"), MB_OK);
                return -1;
            }
            break;
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);

            if(bMotionDetected)
                DrawText(hdc, TEXT("RECORDING"), -1, &(ps.rcPaint), DT_CENTER | DT_VCENTER);
            else
            {
                hbrush = CreateSolidBrush(crWhite);
                FillRect(hdc, &ps.rcPaint, hbrush);
                DeleteObject(hbrush);
            }
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            g_VideoCaptureGraph.Cleanup();
            PostQuitMessage(0);
            break;
        case WM_TIMER:
            dwCurrentTime = GetTickCount();
            dwTimeElapsed = 0;
            
            if(dwCurrentTime > dwMotionDetectedTimeStart)
                dwTimeElapsed = dwCurrentTime - dwMotionDetectedTimeStart;
            else
                dwTimeElapsed = dwCurrentTime + (MAX_DWORD - dwMotionDetectedTimeStart);

            if(dwTimeElapsed >= MotionTimeout)
            {
                KillTimer(hWnd, 1);
                bMotionDetected = FALSE;
                OutputDebugString(TEXT("Stopping the capture"));
                g_VideoCaptureGraph.StopCapture();
            }

            // make sure we update the window.
            InvalidateRect(hWnd, NULL, FALSE);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(
    HINSTANCE hInstance, 
    HINSTANCE hPrevInstance, 
    LPWSTR lpszCmdLine,
    int nCmdShow)
{
    MSG msg;
    WNDCLASS wc;
    HWND hWnd = NULL;
    TCHAR *tszWindowClass = TEXT("MotionApp");
    TCHAR *tszTitle = TEXT("Motion Detection App");

    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = 0;
    wc.hCursor       = 0;
    wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  = 0;
    wc.lpszClassName = tszWindowClass;

    if(RegisterClass(&wc))
    {
        hWnd = CreateWindow(tszWindowClass, tszTitle, WS_VISIBLE | WS_CLIPCHILDREN | WS_BORDER | WS_CAPTION | WS_SYSMENU,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

        if(hWnd)
        {
            ShowWindow(hWnd, nCmdShow);
            UpdateWindow(hWnd);
            SetForegroundWindow(hWnd);

            while (GetMessage(&msg, NULL, 0, 0)) 
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        else MessageBox(NULL, TEXT("CreateWindow failed, exiting"), TEXT("Error"), MB_OK);
    }
    else MessageBox(NULL, TEXT("Failed to register the class, exiting"), TEXT("Error"), MB_OK);

    return 0;
}

